#ifndef CRANKCAMCONTROLLER_H_
#define CRANKCAMCONTROLLER_H_

#include "Timer.h"
#include "Buffer.h"

#define MAX_TOOTH 360

//---------------------------------------------
extern bool almostEqual (int n, int m);

class CrankCamController {
public:
	typedef Buffer<bool, MAX_TOOTH> MaskBufType;
	typedef Buffer<AngleUnit, MAX_TOOTH> AngleBufType;
	typedef Buffer<TimeUnit, MAX_TOOTH> TimeBufType;
private:
	const unsigned short numTooth;
	const unsigned short maxMissingTooth;
	const AngleUnit firstToothOffset;
	const Timer& timer;


	/**
	 * static parameter holding bit tooth pattern like '11111111_1__' for wheel 12-1-2
	 * or  ___1__1___ for some odd uneven double trigger
	 */
	const MaskBufType toothMask;
	MaskBufType::const_iterator toothMaskPos;

	/**
	 * static parameter holding angles offset without respect to first tooth shift
	 * number of elements should be equal to number of set bits in @toothMask
	 */
	AngleBufType angleMask;
	AngleBufType::const_iterator angleMaskPos;

	/**
	 * dynamic parameter, circular buffer containing recorded diffs between toth events
	 * number of elements should be equal to number of set bits in @toothMask
	 */
	Buffer<TimeUnit, MAX_TOOTH> diffBuffer;
	Buffer<TimeUnit, MAX_TOOTH>::iterator diffBufferPos;



	//in tenths of degree, always positive
	AngleUnit lastFixedAngle;
	TimeUnit lastFixedTime;

	//-1 until intialization is finished
	TimeUnit revolutionPeriod;
	TimeUnit averageToothTime;
public:
	bool isInSync;

public:
	CrankCamController(
			const Timer& _timer,
			const MaskBufType& toothPattern,
			AngleUnit _firstToothOffset = 0,
			size_t missing_tooths = 1);
	~CrankCamController();
//    template<class TT> void printDiffBuffer(TT buff);

	void interruptToothEvent();
	AngleUnit predictAngleForTime(TimeUnit time);
	TimeUnit predictTimeForAngle(AngleUnit angle);
	AngleUnit getCurrentAngle();
	void reset();

private:
	bool checkToothsPattern() ;
};

#endif /* CRANKCAMCONTROLLER_H_ */
